﻿using System;
using System.Configuration;
using System.Net;
using System.Net.Sockets;

namespace EasyComm.Utilities
{
    public enum ProtocolScheme
    {
        Http,
        Tcp,
        MsmqNative,
        MsmqSRMP,
        Pipe
    }

    public static class NetUtils
    {
        public static Uri GetAvailableLocalEndPoint(string key, string urlSuffix = "", ProtocolScheme protocolType = ProtocolScheme.Http, string hostName = "", bool readFromConfig = true, bool saveToConfig = true)
        {
            string configUrl = readFromConfig ? ConfigurationManager.AppSettings[key] : null;
            if (!string.IsNullOrWhiteSpace(configUrl))
            {
                return new Uri(configUrl);
            }

            Uri url = null;

            if (string.IsNullOrWhiteSpace(hostName))
            {
                hostName = Environment.MachineName;
            }

            switch (protocolType)
            {
                case ProtocolScheme.Http:
                    url = new Uri(string.Format("http://{0}:{1}/{2}", hostName, GetAvailableTCPPort(), urlSuffix));
                    break;
                case ProtocolScheme.Tcp:
                    url = new Uri(string.Format("net.tcp://{0}:{1}/{2}", hostName, GetAvailableTCPPort(), urlSuffix));
                    break;
                case ProtocolScheme.MsmqNative:
                    url = new Uri(string.Format("net.msmq://{0}/{1}", hostName, urlSuffix));
                    break;
                case ProtocolScheme.MsmqSRMP:
                    url = new Uri(string.Format("net.msmq://{0}:{1}/{2}", hostName, GetAvailableTCPPort(), urlSuffix));
                    break;
                case ProtocolScheme.Pipe:
                    url = new Uri(string.Format("net.pipe://{0}:{1}/{2}", hostName, GetAvailableTCPPort(), urlSuffix));
                    break;
                default:
                    url = new Uri(string.Format("http://{0}:{1}/{2}", hostName, GetAvailableTCPPort(), urlSuffix));
                    break;
            }

            if (saveToConfig)
            {
                System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                KeyValueConfigurationElement endPointUrl = config.AppSettings.Settings[key];
                if (endPointUrl == null)
                {
                    config.AppSettings.Settings.Add(key, url.ToString());
                }
                else
                {
                    endPointUrl.Value = url.ToString();
                }
                config.Save(ConfigurationSaveMode.Full);
                ConfigurationManager.RefreshSection("appSettings");
            }
            return url;
        }

        private static int GetAvailableTCPPort()
        {
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
            using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                try
                {
                    socket.Bind(endPoint);
                    IPEndPoint local = (IPEndPoint)socket.LocalEndPoint;
                    return local.Port;
                }
                catch { return GetAvailableTCPPort(); }
            }
        }

        public static bool TCPOnlineCheck(string hostName, int port)
        {
            bool success = false;
            using (TcpClient tcpScan = new TcpClient())
            {
                try
                {
                    tcpScan.Connect(hostName, port);
                    success = true;
                }
                catch
                {
                }
                finally
                {
                    tcpScan.Close();
                }
            }
            return success;
        }
    }
}
